# connect4.s
# main file
#
# connect4-nios2 project
#
# requires - vga.s

.data

.global main
.text

main:

	call init

	call VGA_BLANK_SCREEN

	movi r4, 5		# startx
	movi r5, 5		# starty
	movi r6, 10		# endx
	movi r7, 10		# endy
	movi r8, 0b100	# red
	subi sp, sp, 4
	stw r8, 0(sp)
	call VGA_DRAW_BOX

	call CLEAR_BOARD

	call PS2_CLEAR_BUF

	# set up ps2 interrupt
	call PS2_SET_INT

	# enable global interrupts
	movi r4, 1
	wrctl ctl0, r4

mainloop:

	call VGA_BLANK_SCREEN
	call vga_draw_board_c

	br mainloop

CLEAR_BOARD:
	# clears the board array
	subi sp, sp, 20
	stw ra, 0(sp)
	stw r8, 4(sp)	# only store r8-r11
	stw r9, 8(sp)
	stw r10, 12(sp)
	stw r11, 16(sp)

	movia r6, array
	movi r7, 0	# x
	movi r8, 0	# y
	movi r9, 7	# x bound
	movi r10, 6	# y bound

	CLR_LOOPY:
		CLR_LOOPX:
			beq r7, r9, CLR_DONE_X	# while
			
			# calculate array offset
			mul r11, r8, r9		# multiply by row
			add r11, r11, r7		# add x
			add r11, r11, r6		# offset from array

			stw r0, 0(r11)		# clear piece at offset

			addi r7, r7, 1	# increment x
			br CLR_LOOPX
		CLR_DONE_X:
	movi r7, 0
	beq r8, r10, CLR_DONE_Y	# while
	addi r8, r8, 1	# increment y
	br CLR_LOOPY
	CLR_DONE_Y:


	ldw r8, 4(sp)
	ldw r9, 8(sp)
	ldw r10, 12(sp)
	ldw r11, 16(sp)
	ldw ra, 0(sp)
	addi sp, sp, 20
	ret

BOARD_SET_PIECE:
	# sets a (column, row) to a value
	# r4 - col, r5 - row, r6 - value
	subi sp, sp, 8
	stw ra, 0(sp)
	stw r11, 4(sp)

	movia r7, array
			
	# calculate array offset
	muli r11, r5, 7		# multiply by row
	add r11, r11, r4		# add x
	add r11, r11, r7		# offset from array

	#andi r6, r6, 0xff		# extract byte
	stw r6, 0(r11)		# set piece at offset to value (r6)


	ldw r11, 4(sp)
	ldw ra, 0(sp)
	addi sp, sp, 8
	ret

.section .exceptions, "ax"
int_handler:

	# r2 - r6
	subi sp, sp, 56
	stw ra, 0(sp)
	stw r2, 4(sp)
	stw r3, 8(sp)
	stw r4, 12(sp)
	stw r5, 16(sp)
	stw r6, 20(sp)
	# store caller saved regs
	stw r8, 24(sp)
	stw r9, 28(sp)
	stw r10, 32(sp)
	stw r11, 36(sp)
	stw r12, 40(sp)
	stw r13, 44(sp)
	stw r14, 48(sp)
	stw r15, 52(sp)

	# check which device caused the interrupt
	rdctl r5, ctl4
	andi r4, r5, 0x800		# check if the ps/2 caused the interrupt
	bne r4, r0, INT_PS2
	andi r4, r5, 0x20		# check if pushbuttons caused the interrupt
	bne r4, r0, INT_PUSHBUTTON
	
	INT_PS2:

	call PS2_CHECK_INT
	beq r2, r0, DONE_PS2_INT	# check if it was a ps/2 read interrupt
	
	call PS2_READ_DATA
	mov r4, r2	# copy read data to r4 - pass argument
	call PS2_STOR_BUF
	
	# now, check the ps2 read buffer and determine what to do
	
	# read the first byte. if F0 - 'break code', wait until next byte comes in
	call PS2_GET_BUF_BYTE_1
	mov r3, r2	# move result to r3 (used later)
	movi r5, 0xF0
	beq r3, r5, DONE_PS2_INT

	call PS2_GET_BUF_BYTE_2		# check previous received byte for F0 (break)
	movi r5, 0xF0
	bne r2, r5, GOT_MAKE_CODE
	
	# we got a break code
	GOT_BREAK_CODE:
	# set a flag? nah
	br DONE_PS2_INT
	
	GOT_MAKE_CODE:
	# check if the same key was pressed twice - if so do nothing
	######beq r2, r3, DONE_PS2_INT
	
	# now compare with all possible keys we're using and do something
	
	movi r5, 0
	movi r6, 0x16	# 1
	beq r3, r6, DO_TURN
	
	movi r5, 1
	movi r6, 0x1E	# 2
	beq r3, r6, DO_TURN
	
	movi r5, 2
	movi r6, 0x26	# 3
	beq r3, r6, DO_TURN
	
	movi r5, 3
	movi r6, 0x25	# 4
	beq r3, r6, DO_TURN
	
	movi r5, 4
	movi r6, 0x2E	# 5
	beq r3, r6, DO_TURN
	
	movi r5, 5
	movi r6, 0x36	# 6
	beq r3, r6, DO_TURN
	
	movi r5, 6
	movi r6, 0x3D	# 7
	beq r3, r6, DO_TURN
	
	movi r5, 7
	movi r6, 0x3E	# 8
	beq r3, r6, DO_TURN
	
	br DONE_PS2_INT		# didn't match the key
	
	DO_TURN:
	# now place piece in column specified by r5
	movia r6, player_turn
	ldw r4, 0(r6)
	call dropPieceInColumn		# r4 player, r5 col
	
	call checkConnect4
	movia r6, game_status
	stw r2, 0(r6)	# update game status
	
	br DONE_INT

	DONE_PS2_INT:
	br DONE_INT
	
	INT_PUSHBUTTON:
	
	call PUSHBUTTON_CHECK_INT
	andi r4, r2, 0b1000
	bne r4, r0, DECR_COL
	andi r4, r2, 0b1
	bne r4, r0, INCR_COL
	andi r4, r2, 0b10
	beq r4, r0, DONE_INT	# if key[1] not set, we're done
	movia r6, curr_col	# get curr col
	ldw r5, 0(r6)
	br DO_TURN			# do turn on this col
	
		DECR_COL:	# decrement column
		call inc_col
		br DONE_INT
		
		INCR_COL:	# increment column
		call inc_col
		br DONE_INT
	
	DONE_INT:

	ldw r8, 24(sp)
	ldw r9, 28(sp)
	ldw r10, 32(sp)
	ldw r11, 36(sp)
	ldw r12, 40(sp)
	ldw r13, 44(sp)
	ldw r14, 48(sp)
	ldw r15, 52(sp)
	#
	ldw ra, 0(sp)
	ldw r2, 4(sp)
	ldw r3, 8(sp)
	ldw r4, 12(sp)
	ldw r5, 16(sp)
	ldw r6, 20(sp)
	addi sp, sp, 56
	subi ea, ea, 4
	eret

# eof
